#include <iostream>
#include <boost/asio/io_context.hpp>

#include "common/logger.hpp"
#include "common/entity/terminal_registration.hpp"
#include "network/client.hpp"
#include "network/server.hpp"
#include "protocol/message/jtt808_header.hpp"
#include "protocol/message/jtt808_packet.hpp"

#include "mysqlx/xdevapi.h"
#include "common/storage.hpp"
#include <sdkddkver.h>



void handler(protocol::Packet packet) {
    std::cout << "Received a jtt808 packet\n" << packet->toString() << std::endl;
}

void insert_terminal(const common::Bytes<15> &imei,
                     const common::Bytes<11> &manufacturer_id,
                     const common::Bytes<30> &terminal_type,
                     const common::Bytes<30> &terminal_id) {
    common::Storage storage;
    mysqlx::bytes v1(imei.bytes,size(imei));
    mysqlx::bytes v2(manufacturer_id.bytes,size(manufacturer_id));
    mysqlx::bytes v3(terminal_type.bytes,size(terminal_type));
    mysqlx::bytes v4(terminal_id.bytes,size(terminal_id));
    storage.insert("terminal", {v1, v2, v3, v4}, {"imei", "manufacturer_id", "terminal_type","terminal_id"});
}

void insert_car(const std::string &license, uint8_t license_color) {
    mysqlx::bytes color(&license_color, 1);
    common::Storage storage;
    storage.insert("car", {license, color}, {"license", "license_color"});
}

int main(int argc, char *argv[])
{
    std::cout << "Hello World!" << std::endl;

    // try {
    //     insert_terminal("0x1212", "0x5678", "0x9abc", "0xcdcd");
    //     insert_car("ANF20388", 2);
    // } catch (const std::exception &e) {
    //     std::cout << e.what() << std::endl;
    // }
    // try {
    //     common::Storage storage("supervisor");
    //     auto bdp = std::make_shared<protocol::terminal::Registeration>(
    //     1, 2, "0xff", "0xff", "0xff", 3, "NF20388");
    //     mysqlx::bytes manu_id(bdp->manufacturer_id_.bytes, size(bdp->manufacturer_id_));
    //     mysqlx::bytes ter_id(bdp->terminal_id_.bytes, size(bdp->terminal_id_));
    //     mysqlx::bytes license_color(&bdp->license_color_, 1);
    //     common::Bytes<11> bytes("0xff");
    //     mysqlx::bytes sql_bytes(bytes.bytes, bytes.bytes+11);
    //     storage.insert("car", {bdp->license_, license_color}, {"license", "license_color"});
    //     auto res = storage.select("terminal", "*", "imei=:p", {{"p", sql_bytes}});
    //     for (auto re : res) {
    //         std::cout << re[0] << "  " << common::toHex(re[1].getRawBytes().first, 11) << std::endl;
    //         bool b = std::equal(re[1].getRawBytes().begin(), re[1].getRawBytes().end(), bytes.bytes, bytes.bytes+10);
    //         std::cout << b << std::endl;
    //     }
    //     // storage.update("terminal", {{"city", 4}, {"terminal_type", "11"}}, "id=2");
    //     // storage.remove("terminal","id>3");
    //     // storage.insert("terminal", res);
    //     // common::Storage storage2("world");
    //     // auto res2 = storage2.select("city", "*", "id<10");
    //     // for (auto row : res2) {
    //     //     std::cout << row[0] << "  " << row[1] << std::endl;
    //     // }
    //     // table.insert().values(1,1,2,"1212", "12", "123133", 1, "nf20388", "12123").execute();
    // } catch (const mysqlx::Error error) {
    //     std::cerr << "Error: " << error << std::endl;
    // }


    std::cout << "Hello, World!" << std::endl;
    const logger_t logger = common::Logger::logger("main");
    logger->debug("hello, World!");
    asio::io_context io_context;

    const std::vector<std::string> args(argv+1, argv+argc);
    if (args.empty()) {
        std::cerr << "Usage: " << argv[0] << " [-s | server | -c | client]" << std::endl;
        return 1;
    }

    if (args[0] == "-s" || args[0] == "superior") {
        std::cout << "###################  Server Mode  ##################" << std::endl;
        uint16_t listen_on = 12345;
        if (argc == 3)
            listen_on = std::stoi(args[1]);
        network::Server server(io_context, listen_on);
        io_context.run();
    } else if (args[0] == "-c" || args[0] == "client") {
        std::cout << "#################  Client Mode  ####################" << std::endl;
        std::string host = "localhost", port = "12345";
        network::Client client(io_context, host, port);
        std::thread t([&]{io_context.run();});
        auto bd1 = std::make_shared<protocol::terminal::Registeration>(1,2,"0x5678", "0x9abc", "0xcdcd",2, "ANF20388");
        client.signup(bd1);
        auto verify_code = common::Container<char>("GNF20388");
        auto bd = std::make_shared<protocol::terminal::Verification>((uint8_t)verify_code._size, verify_code, "0x1234", "0xff");
        client.login(bd);
        auto bd2 = std::make_shared<protocol::terminal::ServerTimeReq>();
        client.send(bd2);
        // auto factory = protocol::PacketFactory::factory(host+"client");
        // auto bd1 = std::make_shared<protocol::terminal::Registeration>(1,2,"0x5678", "0x9abc", "0xcdef",2, "GNF20388");
        // auto packet1 = factory->packet(bd1, {false, false, common::size_of(bd1)});
        // client.send(packet1);
        // client.wait_for_next(protocol::MessageFactory::response_message_id_map[bd1->message_id_]);
        // std::thread t1([&]() {
        //     client.wait_for_next(0x1111);
        // });
        // std::thread t2([&]() {
        //     client.wait_for_next(0x2222);
        // });
        // t1.detach();
        // t2.detach();
        // auto verify_code = common::Container<char>("GNF20388");
        // auto bd = std::make_shared<protocol::terminal::Verification>(verify_code._size, verify_code, "0x1234", "0xff");
        // auto packet = factory->packet(bd, {false, false, common::size_of(bd)});
        // client.deliver(packet);
        // auto bd2 = std::make_shared<protocol::terminal::Logout>();
        // auto packet2 = factory->packet(bd2, {false, false, common::size_of(bd2)});
        // client.deliver(packet2);
        // do {
        //     std::string to_write;
        //     std::cin >> to_write;
        //     if (to_write == "q")
        //         break;
        //     client.deliver(to_write);
        // } while (true);
        // client.stop();
        t.join();
        // 由于客户端逻辑可能需要循环处理事件，所以也需要运行io_context
        // io_context.run();
    } else {
        std::cerr << "Unknown option: " << args[0] << std::endl;
        std::cerr << "Usage: " << argv[0] << " [-s | -c]" << std::endl;
        return 1;
    }

    return 0;
}
